package com.bjwl.modules.common.service.impl;

import com.bjwl.modules.common.service.FileManger;
import com.bjwl.modules.common.pojo.FileInfoDTO;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 作者 Administrator<br/>
 * 创建时间: 2021/11/28<br/>
 * 描述: <br/>
 */
@Component("fileManger")
public class FileMangerImpl implements FileManger {
    protected Path rootLocation = Paths.get("upload-dir");

    public FileInfoDTO fileSave(MultipartFile file) {
        FileInfoDTO fileInfoDto = new FileInfoDTO();
        Map tip = tip(file);
        fileInfoDto.setFilePath(tip.get("savepath").toString());
        fileInfoDto.setFileName(tip.get("filename").toString());
        return fileInfoDto;
    }

    //获取文件
    public void getFile(String filename, HttpServletRequest request, HttpServletResponse response) throws IOException {
        Path file = Paths.get(filename);
        Resource resource = new UrlResource(file.toUri());
        sendData(filename, resource, request, response);
    }

    public void sendData(String filename, Resource resource, HttpServletRequest request, HttpServletResponse response) {
        try (RandomAccessFile randomFile = new RandomAccessFile(resource.getFile(), "r")) {
            long contentLength = randomFile.length();
            String range = request.getHeader("Range");
            long start = 0, end = 0;
            if (range != null && range.startsWith("bytes=")) {
                String[] values = range.split("=")[1].split("-");
                start = Long.parseLong(values[0]);
                if (values.length > 1) {
                    end = Long.parseLong(values[1]);
                }
            }
            long requestSize = 0;
            if (end != 0 && end > start) {
                requestSize = end - start + 1;
            } else {
                requestSize = Long.MAX_VALUE;
            }
            byte[] buffer = new byte[1024];
            //设置响应报文类型
            response.setContentType("");
            response.setHeader("Accept-Ranges", "bytes");
            response.setHeader("ETag", filename);
            response.setHeader("Last-Modified", new Date().toString());
            // 第一次请求只返回content length来让客户端请求多次实际数据
            if (range == null) {
                response.setHeader("Content-length", contentLength + "");
            } else {
                // 以后的多次以断点续传的方式来返回视频数据
                response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);// 206
                long requestStart = 0, requestEnd = 0;
                String[] ranges = range.split("=");
                if (ranges.length > 1) {
                    String[] rangeDatas = ranges[1].split("-");
                    requestStart = Long.parseLong(rangeDatas[0]);
                    if (rangeDatas.length > 1) {
                        requestEnd = Long.parseLong(rangeDatas[1]);
                    }
                }
                long length = 0;
                if (requestEnd > 0) {
                    length = requestEnd - requestStart + 1;
                    response.setHeader("Content-length", "" + length);
                    response.setHeader("Content-Range",
                            "bytes " + requestStart + "-" + requestEnd + "/" + contentLength);
                } else {
                    length = contentLength - requestStart;
                    response.setHeader("Content-length", "" + length);
                    response.setHeader("Content-Range",
                            "bytes " + requestStart + "-" + (contentLength - 1) + "/" + contentLength);
                }
            }
            ServletOutputStream out = response.getOutputStream();
            long needSize = requestSize;
            randomFile.seek(start);
            while (needSize > 0) {
                int len = randomFile.read(buffer);
                if (needSize < buffer.length) {
                    out.write(buffer, 0, (int) needSize);
                } else {
                    out.write(buffer, 0, len);
                    if (len < buffer.length) {
                        break;
                    }
                }
                needSize -= buffer.length;
            }
            out.close();
        } catch (Exception e) {
        }
    }

    /**
     * @param file
     * @return savepath  存取路径
     */
    private Map tip(MultipartFile file) {
        String md5Hex = null;
        try {
            //获取文件的MD5值
            md5Hex = DigestUtils.md5Hex(file.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }

        Map map = new HashMap();
        String filename = StringUtils.cleanPath(file.getOriginalFilename());
        map.put("filename", filename);
        map.put("md5Hex", md5Hex);
        try {
            if (file.isEmpty()) {
                System.out.println("Failed to store empty file " + filename);
            }
            if (filename.contains("..")) {
                // This is a security check
                System.out.println("Cannot store file with relative path outside current directory " + filename);
            }
            Path savepath = this.rootLocation.resolve(filename);
            //判断文件路径是否存在
            File folder = new File(this.rootLocation.toString());
            if (!folder.exists()) {
                folder.mkdirs();
            }
            InputStream inputStream = file.getInputStream();
            //为防止同名文件覆盖，考虑将文件路径加上本身MD5值
            Files.copy(inputStream, savepath, StandardCopyOption.REPLACE_EXISTING);
            map.put("savepath", savepath);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }
}
